using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;

namespace RTR.Transform.VertexBlend
{
    /// <summary>
    /// Entry Point
    /// </summary>
    public class Game : MonoBehaviour
    {
        /// <summary>
        /// 上臂宽高(x: 宽 y: 高)
        /// </summary>
        public Vector2 upperArm = new Vector2(2.0f, 5.0f);
        /// <summary>
        /// 上臂摆动速率
        /// </summary>
        [Range(10.0f, 50.0f)]
        public float upperArmSpeed = 30.0f;
        /// <summary>
        /// 关节长度
        /// </summary>
        [Range(10.0f, 50.0f)]
        public float jointLength = 2.0f;
        /// <summary>
        /// 前臂宽高(x: 宽 y: 高)
        /// </summary>
        public Vector2 forearm = new Vector2(2.0f, 5.0f);
        /// <summary>
        /// 前臂摆动速率
        /// </summary>
        [Range(10.0f, 50.0f)]
        public float forearmSpeed = 30.0f;
        /// <summary>
        /// 手臂材质
        /// </summary>
        public Material armMaterial;

        private Matrix4x4 armMatrix = Matrix4x4.identity;

        private Vector3 upperArmRotate = Vector3.zero;
        private Vector3 forearmRotate = Vector3.zero;

        private void Update()
        {
            // W/S控制上臂左右摆动
            if (Input.GetKey(KeyCode.W))
            {
                upperArmRotate.z -= upperArmSpeed * Time.deltaTime;
            }
            else if (Input.GetKey(KeyCode.S))
            {
                upperArmRotate.z += upperArmSpeed * Time.deltaTime;
            }
            // A/D控制前臂左右摆动
            else if (Input.GetKey(KeyCode.A))
            {
                forearmRotate.z -= forearmSpeed * Time.deltaTime;
            }
            else if (Input.GetKey(KeyCode.D))
            {
                forearmRotate.z += forearmSpeed * Time.deltaTime;
            }
        }

        /// <summary>
        /// 每一帧都有clear，所以需要每一帧重新绘制
        /// </summary>
        private void LateUpdate()
        {
            // 创建一个2D的手臂Mesh
            var armSkeletonModel = CreateArmSkeletonModel2D();
            VertexBlendInCPU(armSkeletonModel);
            var armMesh2D = CreateArmMesh2D(armSkeletonModel);
            Graphics.DrawMeshInstanced(armMesh2D, 0, armMaterial, new[] { armMatrix});
        }

        /// <summary>
        /// 创建2D的手臂骨架模型
        /// </summary>
        /// <returns></returns>
        private SkeletonModel CreateArmSkeletonModel2D()
        {
            var bones = new List<Bone>();
            var vertices = new List<Vertex>();
            // 两根骨骼，每根依附4个顶点
            
            // 骨骼
            // upper arm骨骼
            var upperArmBone = new Bone
            {
                localMatrix = Matrix4x4.Translate(new Vector3(0, jointLength * 0.5f + upperArm.y, 0)),
                parentMatrix = Matrix4x4.identity
            };
            upperArmBone.local2WorldMatrix = upperArmBone.parentMatrix * upperArmBone.localMatrix;
            upperArmBone.world2LocalMatrix = upperArmBone.local2WorldMatrix.inverse;
            // forearm骨骼，是upper arm的子骨骼
            var forearmBone = new Bone
            {
                localMatrix = Matrix4x4.Translate(
                    new Vector3(0, -(jointLength * 0.5f + upperArm.y), 0)),
                parentMatrix = upperArmBone.parentMatrix * upperArmBone.localMatrix
            };
            forearmBone.local2WorldMatrix = forearmBone.parentMatrix * forearmBone.localMatrix;
            forearmBone.world2LocalMatrix = forearmBone.local2WorldMatrix.inverse;

            // 顶点
            // 上-左下，依附两根骨骼
            var u1Vertex = new Vertex
            {
                bones = new List<Bone> { upperArmBone, forearmBone },
                weights = new List<float> { 0.66f, 0.33f },
                localPosition = new Vector3(-upperArm.x * 0.5f, -upperArm.y, 0),
            };
            u1Vertex.CalcWorldPosition();
            // 上-左上，依附一根骨骼
            var u2Vertex = new Vertex
            {
                bones = new List<Bone> { upperArmBone },
                weights = new List<float> { 1.0f },
                localPosition = new Vector3(-upperArm.x * 0.5f, 0, 0),
            };
            u2Vertex.CalcWorldPosition();
            // 上-右上，依附一根骨骼
            var u3Vertex = new Vertex
            {
                bones = new List<Bone> { upperArmBone },
                weights = new List<float> { 1.0f },
                localPosition = new Vector3(upperArm.x * 0.5f, 0, 0),
            };
            u3Vertex.CalcWorldPosition();
            // 上-右下，依附两根骨骼
            var u4Vertex = new Vertex
            {
                bones = new List<Bone> { upperArmBone, forearmBone },
                weights = new List<float> { 0.66f, 0.33f },
                localPosition = new Vector3(upperArm.x * 0.5f, -upperArm.y, 0),
            };
            u4Vertex.CalcWorldPosition();
            // 下-左下，依附一根骨骼
            var u5Vertex = new Vertex
            {
                bones = new List<Bone> { forearmBone },
                weights = new List<float> { 1.0f },
                localPosition = new Vector3(-forearm.x * 0.5f, -forearm.y, 0),
            };
            u5Vertex.CalcWorldPosition();
            // 下-左上，依附两根骨骼
            var u6Vertex = new Vertex
            {
                bones = new List<Bone> { forearmBone, upperArmBone },
                weights = new List<float> { 0.66f, 0.33f },
                localPosition = new Vector3(-forearm.x * 0.5f, 0, 0),
            };
            u6Vertex.CalcWorldPosition();
            // 下-右上，依附两根骨骼
            var u7Vertex = new Vertex
            {
                bones = new List<Bone> { forearmBone, upperArmBone },
                weights = new List<float> { 0.66f, 0.33f },
                localPosition = new Vector3(forearm.x * 0.5f, 0, 0),
            };
            u7Vertex.CalcWorldPosition();
            // 下-右下，依附一根骨骼
            var u8Vertex = new Vertex
            {
                bones = new List<Bone> { forearmBone },
                weights = new List<float> { 1.0f },
                localPosition = new Vector3(forearm.x * 0.5f, -forearm.y, 0),
            };
            u8Vertex.CalcWorldPosition();
            
            bones.Add(upperArmBone);
            bones.Add(forearmBone);
            vertices.Add(u1Vertex);
            vertices.Add(u2Vertex);
            vertices.Add(u3Vertex);
            vertices.Add(u4Vertex);
            vertices.Add(u5Vertex);
            vertices.Add(u6Vertex);
            vertices.Add(u7Vertex);
            vertices.Add(u8Vertex);

            return new SkeletonModel
            {
                bones = bones,
                vertices = vertices
            };
        }

        /// <summary>
        /// 根据SkeletonModel创建一个2D的手臂Mesh，包括上臂、关节和下臂
        /// 上臂是两个三角形，前臂也是两个三角形，
        /// 关节部分分别使用上臂最下面和前臂最上面的两个顶点
        /// 组成两个三角形
        ///  ____
        /// |\  |
        /// | \ |
        /// |  \|
        /// -----
        /// |   |
        /// -----
        /// |\  |
        /// | \ |
        /// |  \|
        /// -----
        /// </summary>
        /// <returns>手臂Mesh</returns>
        private Mesh CreateArmMesh2D(SkeletonModel skeletonModel)
        {
            var mesh = new Mesh();
            var vertices = new List<Vector3>();
            var indices = new List<int>();
            
            // 注意 unity里面，顶点wrap顺序是顺时针
            
            // 左下
            vertices.Add(skeletonModel.CalcVertexPosition(0));
            // 左上
            vertices.Add(skeletonModel.CalcVertexPosition(1));
            // 右上
            vertices.Add(skeletonModel.CalcVertexPosition(2));
            // 右下
            vertices.Add(skeletonModel.CalcVertexPosition(3));
            indices.Add(0);
            indices.Add(1);
            indices.Add(2);
            indices.Add(2);
            indices.Add(3);
            indices.Add(0);
            
            // forearm
            // 左下
            vertices.Add(skeletonModel.CalcVertexPosition(4));
            // 左上
            vertices.Add(skeletonModel.CalcVertexPosition(5));
            // 右上
            vertices.Add(skeletonModel.CalcVertexPosition(6));
            // 右下
            vertices.Add(skeletonModel.CalcVertexPosition(7));
            indices.Add(4);
            indices.Add(5);
            indices.Add(6);
            indices.Add(6);
            indices.Add(7);
            indices.Add(4);
            
            // joint
            indices.Add(5);
            indices.Add(0);
            indices.Add(3);
            indices.Add(3);
            indices.Add(6);
            indices.Add(5);

            mesh.vertices = vertices.ToArray();
            mesh.triangles = indices.ToArray();

            return mesh;
        }

        /// <summary>
        /// CPU侧执行VertexBlend
        /// </summary>
        /// <param name="skeletonModel"></param>
        private void VertexBlendInCPU(SkeletonModel skeletonModel)
        {
            // 每个顶点需要关联n个骨骼，并且相对于每个骨骼有一个权重，权重总和为1
            
            // 先尝试动一下上臂，来个旋转
            var uaMatrix = skeletonModel.bones[0].localMatrix;
            uaMatrix.SetTRS(uaMatrix.GetColumn(3), Quaternion.Euler(upperArmRotate), Vector3.one);
            skeletonModel.bones[0].localMatrix = uaMatrix;
            // 前臂跟着动
            skeletonModel.bones[1].parentMatrix = skeletonModel.bones[0].parentMatrix * uaMatrix;

            // 前臂运动
            var faMatrix = skeletonModel.bones[1].localMatrix;
            faMatrix.SetTRS(faMatrix.GetColumn(3), Quaternion.Euler(forearmRotate), Vector3.one);
            skeletonModel.bones[1].localMatrix = faMatrix;
        }
    }
}
